﻿using System;
using System.IO;
using System.Net;
using System.Text;
using System.Web;
using System.Xml;
using up6.db.model;

namespace up6.db.store
{
	public class MinioTool
    {
        /// <summary>
        /// API:
        /// https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/API/API_PutObject.html
        /// </summary>
        /// <param name="key">/123.txt</param>
        /// <param name="data"></param>
        /// <returns></returns>
        public static string putObject(string key,byte[] data) {

            string etag = string.Empty;
            MinioConfig cfg = new MinioConfig();
            //WebClient c = new WebClient();
            //OkHttpClient c = new OkHttpClient();
            //http://192.168.0.111:9001/test//123.txt
            string url = cfg.endpoint + "/" + cfg.bucket + "/" + key;
            //MediaType JSON = MediaType.parse("application/octet-stream; charset=utf-8");

            //RequestBody body = RequestBody.create(JSON, data);


            MinioAuthorization auth = new MinioAuthorization();
            auth.setConfig(cfg)
            .setMethod("PUT")
            .setData(data)
            .setUrl(url)
            //.addHead("content-length",data.Length.ToString())
            //.addHead("content-type", "application/octet-stream; charset=utf-8")
            .delHead("content-md5")
            .setContentType("application/octet-stream");

            try
            {
                String authstr = auth.Authorization();
				var req = (HttpWebRequest)WebRequest.Create(new Uri(url));
				req.Method = "PUT";
				req.ContentType = "application/octet-stream";
				req.ContentLength = data.Length;
				req.Headers.Add("x-amz-date", auth.getTimeIso());
				req.Headers.Add("x-amz-content-sha256", auth.data_sha256_Hash);
				req.Headers.Add("Authorization", authstr);
				req.GetRequestStream().Write(data, 0, data.Length);

				using (var res = (HttpWebResponse)req.GetResponse())
				{
					return res.Headers.Get("ETag");
				}
            }
            catch (Exception ex) {
                System.Diagnostics.Debug.WriteLine(ex.Message);
            }
            return etag;
        }
        public static string putObject(string key, string pathLoc)
        {

            string etag = string.Empty;
            MinioConfig cfg = new MinioConfig();
            //WebClient c = new WebClient();
            //OkHttpClient c = new OkHttpClient();
            //http://192.168.0.111:9001/test//123.txt
            string url = cfg.endpoint + "/" + cfg.bucket + "/" + key;
            
            var tp = MimeMapping.GetMimeMapping(pathLoc);
            var data = File.ReadAllBytes(pathLoc);

            MinioAuthorization auth = new MinioAuthorization();
            auth.setConfig(cfg)
            .setMethod("PUT")
            .setData(data)
            .setUrl(url)
            //.addHead("content-length",data.Length.ToString())
            //.addHead("content-type", "application/octet-stream; charset=utf-8")
            .delHead("content-md5")
            .setContentType(tp);

            try
            {
                String authstr = auth.Authorization();
                WebClient c = new WebClient();
                c.Headers.Add("Content-Type", tp);
                //c.Headers.Add("Content-Length", data.Length.ToString());
                c.Headers.Add("x-amz-date", auth.getTimeIso());
                c.Headers.Add("x-amz-content-sha256", auth.data_sha256_Hash);
                c.Headers.Add("Authorization", authstr);
                var stem = c.OpenWrite(url, "PUT");
                if (stem.CanWrite)
                {
                    stem.Write(data, 0, data.Length);
                }
                System.Diagnostics.Debug.WriteLine("签名：" + authstr);
                stem.Close();
                etag = c.ResponseHeaders.Get("ETag");
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
            }
            return etag;
        }


		/**
		 * API：
		 * 	https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/API/API_GetObject.html
		 * @param key 以左斜杠开始的资源路径。/guid/QQ.exe径
		 * @param blockOffset
		 * @param blockLen
		 * @return
		 */
		public static byte[] getObject(string key, long blockOffset, long blockLen)
		{
			MinioConfig cfg = new MinioConfig();
			//http://192.168.0.111:9001/test//123.txt?uploads

			string url = cfg.endpoint + "/" + cfg.bucket + "/" + key;
			string range = "bytes=" + blockOffset.ToString() + "-" + (blockOffset + blockLen - 1).ToString();

			MinioAuthorization auth = new MinioAuthorization();

			auth.setConfig(cfg)
			.setMethod("GET")
			.setData(Encoding.UTF8.GetBytes(""))
			.setUrl(url)
			.delHead("content-length")
			.delHead("content-type")
			.delHead("Content-Md5");
			//.setContentType("application/octet-stream; charset=utf-8");

			var authstr = auth.Authorization();

			HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
			req.ContentType = "application/octet-stream; charset=utf-8";
			req.Method = "GET";
			req.Headers.Add("x-amz-date", auth.getTimeIso());
			req.Headers.Add("x-amz-content-sha256", auth.getDataHash());
			req.AddRange(blockOffset, blockOffset + blockLen);
			req.Headers.Add("Authorization", authstr);
			HttpWebResponse res = (HttpWebResponse)req.GetResponse();

			/**返回值
			* 	
			HTTP/1.1 206 Partial Content
			x-amz-id-2: MzRISOwyjmnupCzjI1WC06l5TTAzm7/JypPGXLh0OVFGcJaaO3KW/hRAqKOpIEEp
			x-amz-request-id: 47622117804B3E11
			Date: Fri, 28 Jan 2011 21:32:09 GMT
			x-amz-meta-title: the title
			Last-Modified: Fri, 28 Jan 2011 20:10:32 GMT
			ETag: "b2419b1e3fd45d596ee22bdf62aaaa2f"
			Accept-Ranges: bytes
			Content-Range: bytes 0-9/443
			Content-Type: text/plain
			Content-Length: 10
			Server: AmazonS3
		
			[10 bytes of object data]
			*/
			byte[] bt = new byte[res.ContentLength];
			//处理返回值
			using (Stream resStream = res.GetResponseStream())
			{
				using (var reader = new BinaryReader(resStream))
				{
					bt = reader.ReadBytes(bt.Length);
				}
			}
			return bt;
		}

		/**
		 * API：
		 * 	https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/API/API_CreateMultipartUpload.html
		 * @param key guid/QQ.exe，
		 * @return
		 */
		public static String CreateMultipartUpload(String key)
		{
			MinioConfig cfg = new MinioConfig();
			//http://192.168.0.111:9001/test//123.txt?uploads
			String url = cfg.endpoint + "/" + cfg.bucket + "/" + key + "?uploads";

			var mimeType = MimeMapping.GetMimeMapping(key);

			MinioAuthorization auth = new MinioAuthorization();
			auth.setConfig(cfg)
			.setMethod("POST")
			.setData(Encoding.UTF8.GetBytes(""))
			.setUrl(url)
			.delHead("Content-Md5")
			//.delHead("Content-Length")
			.setContentType(mimeType);

			String authstr = auth.Authorization();
			//url = PathTool.url_save_encode(url);
			HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url);
			req.Method = "POST";
			req.ContentLength = 0;
			req.ContentType= mimeType;
			req.Headers.Add("x-amz-date", auth.getTimeIso());
			req.Headers.Add("x-amz-content-sha256", auth.getDataHash());
			req.Headers.Add("Authorization", authstr);

			var res = (HttpWebResponse)req.GetResponse();
			//error
			if (res.StatusCode != HttpStatusCode.OK) return String.Empty;

			var sr = new StreamReader(res.GetResponseStream(),Encoding.UTF8);
			var str = sr.ReadToEnd();
			sr.Close();
			res.Close();
				
			//System.out.println("返回头：\n"+res.headers().toString());

			/**返回值
				<InitiateMultipartUploadResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
					<Bucket>example-bucket</Bucket>
					<Key>example-object</Key>
					<UploadId>VXBsb2FkIElEIGZvciA2aWWpbmcncyBteS1tb3ZpZS5tMnRzIHVwbG9hZA</UploadId>
				</InitiateMultipartUploadResult>
				*/
				
			//System.out.println("返回值："+str);
			XmlDocument doc = new XmlDocument();
			doc.LoadXml(str);

			XmlNamespaceManager nsMgr = new XmlNamespaceManager(doc.NameTable);
			nsMgr.AddNamespace("ns", "http://s3.amazonaws.com/doc/2006-03-01/");

			var uploadId = doc.DocumentElement.SelectSingleNode("//ns:UploadId", nsMgr);
			return uploadId.InnerText;
		}

		/**
		 * API:
		 * 	https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/API/API_UploadPart.html
		 * @param key /guid/QQ.exe
		 * @param part 基于1
		 * @param uploadID
		 * @param data
		 */
		public static String UploadPart(String key, int part, String uploadID, byte[] data)
		{
			//System.out.println("\n 上传片："+key +  " partNumber="+String.valueOf(part)+" UploadId="+uploadID);

			MinioConfig cfg = new MinioConfig();
			//http://192.168.0.111:9001/test//123.txt
			String url = cfg.endpoint + "/" + cfg.bucket + "/" + key + "?partNumber=" + part.ToString() + "&uploadId=" + uploadID;
			//System.out.println("查询字符串：\n"+url);

			MinioAuthorization auth = new MinioAuthorization();
			auth.setConfig(cfg)
			.setMethod("PUT")
			.setData(data)
			.setUrl(url)
			//.delHead("x-amz-content-sha256")
			.delHead("content-md5")
			.delHead("content-type")
			.setContentType("application/octet-stream; charset=utf-8");

			String authstr = auth.Authorization();
			HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
			req.Method = "PUT";
			req.ContentLength=data.Length;
			req.Headers.Add("x-amz-date", auth.getTimeIso());
			req.Headers.Add("x-amz-content-sha256", auth.data_sha256_Hash);
			req.Headers.Add("Authorization", authstr);
			using (var stm = req.GetRequestStream())
            {
				stm.Write(data, 0, data.Length);
			}
			var res = (HttpWebResponse)req.GetResponse();
			//error
			if (res.StatusCode != HttpStatusCode.OK) return String.Empty;

			/**
				* 
				HTTP/1.1 100 Continue   HTTP/1.1 200 OK
				x-amz-id-2: Zn8bf8aEFQ+kBnGPBc/JaAf9SoWM68QDPS9+SyFwkIZOHUG2BiRLZi5oXw4cOCEt
				x-amz-request-id: 5A37448A37622243
				Date: Wed, 28 May 2014 19:40:12 GMT
				ETag: "7e10e7d25dc4581d89b9285be5f384fd"
				x-amz-server-side-encryption-customer-algorithm: AES256
				x-amz-server-side-encryption-customer-key-MD5: ZjQrne1X/iTcskbY2example
				*/
			return res.Headers.Get("ETag").Replace("\"", "");
		}

		/**
		 * 参数：pathSvr,minio_id(UploadId)
		 * API:
		 * 	https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/API/API_CompleteMultipartUpload.html
		 * POST /Key+?uploadId=UploadId HTTP/1.1
			Host: Bucket.s3.amazonaws.com
			<?xml version="1.0" encoding="UTF-8"?>
			<CompleteMultipartUpload xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
			   <Part>
				  <ChecksumCRC32>string</ChecksumCRC32>
				  <ChecksumCRC32C>string</ChecksumCRC32C>
				  <ChecksumSHA1>string</ChecksumSHA1>
				  <ChecksumSHA256>string</ChecksumSHA256>
				  <ETag>string</ETag>
				  <PartNumber>integer</PartNumber>
			   </Part>
			   ...
			</CompleteMultipartUpload>

		 * @param key
		 * @param id
		 */
		public static bool CompleteMultipartUpload(FileInf file)
		{
			//System.out.println("\n minio.合并文件：\n key="+file.S3Key()+"\n UploadId="+file.minio_id);
			MinioConfig cfg = new MinioConfig();
			//http://192.168.0.111:9001/test//123.txt
			String url = cfg.endpoint + "/" + cfg.bucket + "/" + file.S3Key() + "?uploadId=" + file.object_id;
			//System.out.println("查询字符串：\n"+url);

			String etags = file.etags();
			byte[] data = Encoding.UTF8.GetBytes(etags);

			MinioAuthorization auth = new MinioAuthorization();
			auth.setConfig(cfg)
			.setMethod("POST")
			.setUrl(url)
			.setData(data)
			.delHead("Content-Md5")
			.delHead("content-type")
			.setContentType("application/octet-stream; charset=utf-8");

			String authstr = auth.Authorization();
			HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
			req.ContentType = "application/octet-stream; charset=utf-8";
			req.Method = "POST";
			req.ContentLength = data.Length;
			req.Headers.Add("x-amz-date", auth.getTimeIso());
			req.Headers.Add("x-amz-content-sha256", auth.getDataHash());
			req.Headers.Add("Authorization", authstr);
			using (var stm = req.GetRequestStream())
			{
				stm.Write(data, 0, data.Length);
			}

			var res = (HttpWebResponse)req.GetResponse();
			//error
			if (res.StatusCode != HttpStatusCode.OK) return false;

			/*
			 * HTTP/1.1 200
				x-amz-expiration: Expiration
				x-amz-server-side-encryption: ServerSideEncryption
				x-amz-version-id: VersionId
				x-amz-server-side-encryption-aws-kms-key-id: SSEKMSKeyId
				x-amz-server-side-encryption-bucket-key-enabled: BucketKeyEnabled
				x-amz-request-charged: RequestCharged
				<?xml version="1.0" encoding="UTF-8"?>
				<CompleteMultipartUploadResult>
				   <Location>string</Location>
				   <Bucket>string</Bucket>
				   <Key>string</Key>
				   <ETag>string</ETag>
				   <ChecksumCRC32>string</ChecksumCRC32>
				   <ChecksumCRC32C>string</ChecksumCRC32C>
				   <ChecksumSHA1>string</ChecksumSHA1>
				   <ChecksumSHA256>string</ChecksumSHA256>
				</CompleteMultipartUploadResult>
			 */
			//在这里对接收到的页面内容进行处理
			using (Stream resStream = res.GetResponseStream())
			{
				using (StreamReader reader = new StreamReader(resStream, Encoding.UTF8))
				{
					reader.ReadToEnd().ToString();
				}
			}
			return true;
		}
	}
}